package com.starsoft.smdc.crawler.danjuan;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.starsoft.frame.fileimport.JsonReader;
import com.starsoft.frame.fileimport.pojo.Column;
import com.starsoft.frame.fileimport.pojo.DataTable;
import com.starsoft.frame.fileimport.pojo.NullType;
import com.starsoft.frame.fileimport.pojo.Table;
import com.starsoft.frame.fileimport.pojo.Table.TitleType;
import com.starsoft.frame.fileimport.pojo.ValueType;
import com.starsoft.frame.util.DateUtil;
import com.starsoft.frame.util.MapUtil;
import com.starsoft.frame.util.StringUtil;
import com.starsoft.smdc.bean.SmdcMarketDaily;
import com.starsoft.smdc.bean.SmdcMarketDailyId;
import com.starsoft.smdc.bean.SmdcSecurity;
import com.starsoft.smdc.crawler.common.CrawlerService;
import com.starsoft.smdc.crawler.common.MarketDailyCrawler;

@Component
public class MarketDailyCsi extends CrawlerService implements MarketDailyCrawler {

	private static Logger logger = LoggerFactory.getLogger(MarketDailyCsi.class);

	public MarketDailyCsi() {
		this.apiMap = new HashMap<>();
		apiMap.put("fullEarningIndex", "https://www.csindex.com.cn/csindex-home/perf/index-perf?indexCode=%s&startDate=%s&endDate=%s");
	}
	
	@Override
	public List<SmdcMarketDaily> update(SmdcSecurity security, Date begin) {
		return update(Arrays.asList(security), Arrays.asList(begin));
	}

	@Override
	public List<SmdcMarketDaily> update(List<SmdcSecurity> securityList, List<Date> begin) {
		List<SmdcMarketDaily> result = new ArrayList<SmdcMarketDaily>();
		for (int i = 0; i < securityList.size(); i++) {
			SmdcSecurity security = securityList.get(i);
			try {
				List<SmdcMarketDaily> markets = getIndexValuation(security, begin.get(i));
				result.addAll(markets);
				marketDailyDao.saveOrUpdateBatch(markets);
			} catch (Exception e) {
				logger.error("", e);
			}
		}
		return result;
	}
	
	private List<SmdcMarketDaily> getIndexValuation(SmdcSecurity security, Date begin) {
		List<SmdcMarketDaily> markets = new ArrayList<>();
		long count = DateUtil.getDays(begin, new Date());
		if(count<0) {
			return markets;
		}
		JsonReader reader = new JsonReader();
		
		Map<Date, SmdcMarketDaily> marketMap = marketDailyDao.getAfter(security.getSecId(), begin).stream()
				.collect(Collectors.toMap(a -> a.getId().getTradeDate(), a -> a));
		List<SmdcMarketDaily> hisMakkets = marketDailyDao.getAfter(security.getSecId(), DateUtil.bumpDate(begin, -1, 0, 0));
		
		if("csi".equals(security.getExchange())) {
			String fullEarningResponse = this.request("fullEarningIndex", security.getTicker(), DateUtil.toString(begin, "yyyyMMdd"), DateUtil.toString(new Date(), "yyyyMMdd"));
			List<Column> columnList3 = new ArrayList<Column>();
			columnList3.add(new Column("tradeDate", "tradeDate", ValueType.DateTime, NullType.notnull, "yyyyMMdd"));
			columnList3.add(new Column("close", "closePrice", ValueType.Double, NullType.nullable));
			columnList3.add(new Column("open", "openPrice", ValueType.Double, NullType.nullable));
			columnList3.add(new Column("high", "highPrice", ValueType.Double, NullType.nullable));
			columnList3.add(new Column("low", "lowPrice", ValueType.Double, NullType.nullable));
			columnList3.add(new Column("changePct", "percent", ValueType.Double, NullType.nullable));
			Table table3 = new Table(TitleType.Null, columnList3);
			DataTable dataTable3 = reader.read(fullEarningResponse, table3, "data");
			
			for (Map<String, Object> mapObject : dataTable3.getData()) {
				Date tradeDate = (Date) mapObject.get("tradeDate");
				SmdcMarketDaily market = marketMap.get(tradeDate);
				if (market != null) {
					MapUtil.updateBean(market, mapObject);
					market.setPercent(market.getPercent() / 100);
				} else {
					market = new SmdcMarketDaily();
					MapUtil.updateBean(market, mapObject);
					SmdcMarketDailyId id = new SmdcMarketDailyId(security.getSecId(), tradeDate);
					market.setId(id);
					market.setPercent(market.getPercent() / 100);
					marketMap.put(tradeDate, market);
					hisMakkets.add(market);
				}
				markets.add(market);
			}
		}
		if (!StringUtil.isEmpty(security.getFullEarningIndex()) ) {
			String fullEarningResponse = this.request("fullEarningIndex", security.getFullEarningIndex(), DateUtil.toString(begin, "yyyyMMdd"), DateUtil.toString(new Date(), "yyyyMMdd"));
			List<Column> columnList3 = new ArrayList<Column>();
			columnList3.add(new Column("tradeDate", "tradeDate", ValueType.DateTime, NullType.notnull, "yyyyMMdd"));
			columnList3.add(new Column("close", "divi", ValueType.Double, NullType.nullable));
			Table table3 = new Table(TitleType.Null, columnList3);
			DataTable dataTable3 = reader.read(fullEarningResponse, table3, "data");
			
			for (Map<String, Object> mapObject : dataTable3.getData()) {
				Date tradeDate = (Date) mapObject.get("tradeDate");
				SmdcMarketDaily market = marketMap.get(tradeDate);
				if (market != null) {
					market.setDivi((Double) mapObject.get("divi"));
					updateDivi(hisMakkets, market);
					markets.add(market);
				}
			}
		}
		
		return markets;
	}

	private void updateDivi(List<SmdcMarketDaily> hisMarkets, SmdcMarketDaily market) {
		Date tradeDate = market.getId().getTradeDate();
		Date beforeDate = DateUtil.bumpDate(tradeDate, -1, 0, 0);
		List<SmdcMarketDaily> markets = hisMarkets.stream()
				.filter(a -> a.getId().getTradeDate().compareTo(tradeDate) <= 0
						&& a.getId().getTradeDate().compareTo(beforeDate) >= 0)
				.sorted((a, b) -> a.getId().getTradeDate().compareTo(b.getId().getTradeDate()))
				.collect(Collectors.toList());

		if (markets.size() < 200) {
			logger.info("全收益指数收盘价数量太少");
			return;
		}

		double divPT = 0;
		SmdcMarketDaily lastHis = null;
		for (SmdcMarketDaily historyMarket : markets) {
			if (historyMarket.getDivi() == null) {
				logger.info("全收益指数收盘价为空");
				return;
			}
			if (lastHis == null) {
				lastHis = historyMarket;
				continue;
			}

			Double diviP = historyMarket.getDivi() / lastHis.getDivi()
					- historyMarket.getClosePrice() / lastHis.getClosePrice();
			diviP *= historyMarket.getClosePrice();
			divPT += diviP;
			lastHis = historyMarket;
		}
		market.setDiviWeighted(divPT / market.getClosePrice());
	}
	
	
	
	protected String convertSecId(String secId, boolean isToLocal) {
		if (isToLocal) {
			String ticker = secId.substring(2);
			String exchange = secId.substring(0, 2);
			exchange = flexsetService.codeConvertFrom(SMDC_EXCHANGE, exchange, this.getTargetSystem());
			return ticker + "." + exchange;
		} else {
			int index = secId.indexOf(".");
			String ticker = secId.substring(0, index);
			String exchange = secId.substring(index + 1);
			exchange = flexsetService.codeConvertTo(SMDC_EXCHANGE, exchange, this.getTargetSystem());
			return exchange + ticker;
		}
	}

	@Override
	protected String getTargetSystem() {
		return "xueqiu";
	}

}
